﻿// Open Source: MIT License (http://www.opensource.org/licenses/mit-license.php)
// Project: YoProgramo.NET (http://code.google.com/p/yoprogramo/)
// Autor: Fabian Figueredo (info@fabianfigueredo.com.ar)
// Blog: blog.yoprogramo.net

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate.Validator.Engine;
using YoProgramo.Domain.Core.Entities;
using YoProgramo.Domain.Core.Exceptions;
using YoProgramo.Domain.Core.Interfaces;
using YoProgramo.Infrastructure.Tools.NHValidator;

namespace YoProgramo.Domain.BusinessLogic.Service
{
    public class VoteService<Ttentity> : IVoteService<Ttentity> {
        private IVoteRepository<Ttentity> _repository;

        public VoteService (IVoteRepository<Ttentity> r)
        {
            _repository = r;
        }

        #region IVoteService<Ttentity> Members

        public IList<IVote<Ttentity>> GetAll() {
            return _repository.GetAll();
        }

        public NHibernate.Validator.Engine.InvalidValue[] Create(IVote<Ttentity> obj) {
            InvalidValue[] validatorErrors = new NHValidatorWrapper<IVote<Ttentity>>().Validate(obj);

            if (validatorErrors.Count() < 1)
                _repository.SaveOrUpdate(obj);

            return validatorErrors;
        }

        public bool Update(IVote<Ttentity> obj) {
            try {
                _repository.SaveOrUpdate(obj);
                return true;
            } catch {
                return false;
            }
        }

        public void Delete(IVote<Ttentity> obj) {
            _repository.Delete(obj);
        }

        public IList<IVote<Ttentity>> GetVotesBy(Ttentity obj) {
            return (from s in GetAll()
                    where ((IEntityCommon)s.VoteFor).Id == ((IEntityCommon)obj).Id
                    orderby s.PromotedAt descending
                    select s).ToList();
        }

        public IList<IVote<Ttentity>> GetVotesByUser(IUser obj) {
            return (from s in GetAll()
                    where s.ByUser.Equals(obj)
                    orderby s.PromotedAt descending
                    select s).ToList();
        }

        public void VoteFor(Ttentity obj, int rate, IUser user, string ip) {

            if(rate != -1 && rate != 1)
                throw new YPException("Error: Rate only can have this values: -1 or 1");

            if (HasVoted(obj, user))
                throw new YPException("Error: User has voted");

            var vote = new Vote<Ttentity>();
            vote.ByUser = user;
            vote.FromIPAddress = ip;
            vote.PromotedAt = DateTime.Now;
            vote.Rate = rate;
            vote.VoteFor = obj;

            Create(vote);
        }

        public bool HasVoted(Ttentity obj, IUser user) {
            IList<IVote<Ttentity>> votes = (from s in GetVotesByUser(user)
                                            where s.VoteFor.Equals(obj)
                                            select s).ToList();
            if(votes.Count > 0)
                return true;

            return false;            
        }

        public int GetScore(Ttentity obj) {
            IList<IVote<Ttentity>> votes =  GetVotesBy(obj);
            int voteNegatives = (int)votes.Where(x => x.Rate == -1).Count();
            int votePositives = (int)votes.Where(x => x.Rate == 1).Count();

            return votePositives - voteNegatives;
        }

        #endregion
    }
}